package com.fanshilz.flower2025.business.sys.sysUser.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjUtil;
import com.fanshilz.flower2025.apps.admin.satoken.AdminCurrentUser;
import com.fanshilz.flower2025.apps.admin.satoken.StpAdminUtil;
import com.fanshilz.flower2025.apps.admin.sysUser.req.SysUserLoginReq;
import com.fanshilz.flower2025.apps.admin.sysUser.resp.RouteItemResp;
import com.fanshilz.flower2025.business.sys.sysRoute.entity.SysRouteTypeEnum;
import com.fanshilz.flower2025.business.sys.sysRoute.service.ISysRouteService;
import com.fanshilz.flower2025.business.sys.sysUser.entity.SysUser;
import com.fanshilz.flower2025.business.sys.sysUser.entity.UserStatusEnum;
import com.fanshilz.flower2025.business.sys.sysUser.mapper.SysUserMapper;
import com.fanshilz.flower2025.business.sys.sysUser.service.ISysUserService;
import com.fanshilz.flower2025.business.sys.sysUserRole.service.ISysUserRoleService;
import com.fanshilz.flower2025.framework.exception.CodeException;
import com.fanshilz.flower2025.framework.resp.Resp;
import com.fanshilz.flower2025.framework.util.PasswordUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import io.github.linpeilie.Converter;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.fanshilz.flower2025.business.sys.sysRole.entity.table.SysRoleTableDef.SYS_ROLE;
import static com.fanshilz.flower2025.business.sys.sysRoleRoute.entity.table.SysRoleRouteTableDef.SYS_ROLE_ROUTE;
import static com.fanshilz.flower2025.business.sys.sysRoute.entity.table.SysRouteTableDef.SYS_ROUTE;
import static com.fanshilz.flower2025.business.sys.sysUser.entity.table.SysUserTableDef.SYS_USER;
import static com.fanshilz.flower2025.business.sys.sysUserRole.entity.table.SysUserRoleTableDef.SYS_USER_ROLE;

/**
 * 服务层实现。
 *
 * @author fugui
 * @since 2024-09-27
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    @Resource
    private Converter converter;
    @Resource
    private ISysRouteService sysRouteService;
    @Resource
    private ISysUserRoleService sysUserRoleService;

    @Override
    public void login(SysUserLoginReq req) {
        SysUser sysUser = getOne(QueryWrapper.create().where(SYS_USER.LOGIN_NAME.eq(req.getAccount())));
        Assert.notNull(sysUser, () -> new CodeException("用户名密码错误"));

        Assert.isTrue(UserStatusEnum.OK.equals(sysUser.getUserStatus()), () -> new CodeException("用户状态异常"));

        String pwdHash = PasswordUtil.generated(req.getAccount(), sysUser.getPwdSalt(), req.getPassword());
        Assert.isTrue(pwdHash.equals(sysUser.getPwdHash()), () -> new CodeException("用户名密码错误"));

        AdminCurrentUser currentUser = converter.convert(sysUser, AdminCurrentUser.class);

        List<String> roles = sysUserRoleService.listAs(QueryWrapper.create()
                        .select(SYS_ROLE.ROLE_CODE)
                        .innerJoin(SYS_ROLE).on(SYS_ROLE.ROLE_ID.eq(SYS_USER_ROLE.ROLE_ID))
                        .where(SYS_USER_ROLE.USER_ID.eq(sysUser.getUserId())
                                .when(ObjUtil.isNull(sysUser.getSuperAdmin()) || !sysUser.getSuperAdmin()))
                , String.class);

        List<String> codes = sysRouteService.listAs(QueryWrapper.create()
                        .select(SYS_ROUTE.CODE)
                        .innerJoin(SYS_ROLE_ROUTE).on(SYS_ROLE_ROUTE.ROUTE_ID.eq(SYS_ROUTE.ROUTE_ID))
                        .innerJoin(SYS_ROLE).on(SYS_ROLE_ROUTE.ROLE_ID.eq(SYS_ROLE.ROLE_ID))
                        .innerJoin(SYS_USER_ROLE).on(SYS_ROLE.ROLE_ID.eq(SYS_USER_ROLE.ROLE_ID))
                        .where(SYS_USER_ROLE.USER_ID.eq(sysUser.getUserId())
                                .when(ObjUtil.isNull(sysUser.getSuperAdmin()) || !sysUser.getSuperAdmin()))
                , String.class);

        roles.addAll(codes);
        roles = roles.stream().distinct().collect(Collectors.toList());

        if (ObjUtil.isNotNull(sysUser.getSuperAdmin()) && sysUser.getSuperAdmin()) {
            roles.add("super:admin");
        }

        currentUser.setRoles(roles);

        StpAdminUtil.login(currentUser);

    }

    @Override
    public Resp<List<RouteItemResp>> routeList() {
        QueryWrapper qw = QueryWrapper.create()
                .where(SYS_ROUTE.TYPE.in(SysRouteTypeEnum.DIRECTORY, SysRouteTypeEnum.PAGE));
        AdminCurrentUser currentUser = StpAdminUtil.currentUser();

        List<RouteItemResp> all = sysRouteService.getMapper()
                .selectListWithRelationsByQueryAs(qw, RouteItemResp.class);

        boolean superAdmin = ObjUtil.isNotNull(currentUser.getSuperAdmin()) && currentUser.getSuperAdmin();

        if (superAdmin) {
            List<RouteItemResp> newRoutes = findChildren(all, 0L);
            return Resp.success(newRoutes);
        } else {
            qw.select(SYS_ROUTE.ALL_COLUMNS);
            // 普通用户需要加载角色
            qw.innerJoin(SYS_ROLE_ROUTE).on(SYS_ROLE_ROUTE.ROUTE_ID.eq(SYS_ROUTE.ROUTE_ID));
            qw.innerJoin(SYS_ROLE).on(SYS_ROLE.ROLE_ID.eq(SYS_ROLE_ROUTE.ROLE_ID));
            qw.innerJoin(SYS_USER_ROLE).on(SYS_USER_ROLE.ROLE_ID.eq(SYS_ROLE.ROLE_ID));
            qw.where(SYS_USER_ROLE.USER_ID.eq(currentUser.getUserId()));
        }

        List<RouteItemResp> routeItemResps = sysRouteService.getMapper()
                .selectListWithRelationsByQueryAs(qw, RouteItemResp.class);

        // 填充菜单的父菜单
        findParent(routeItemResps, all, 0);
        routeItemResps = routeItemResps.stream().distinct().toList();

        List<RouteItemResp> newRoutes = findChildren(routeItemResps, 0L);
        return Resp.success(newRoutes);
    }

    public void findParent(List<RouteItemResp> routeItemResps, List<RouteItemResp> all, int index) {
        if (index >= routeItemResps.size()) {
            return;
        }
        RouteItemResp routeItemResp = routeItemResps.get(index);
        if (routeItemResp.getParentId() == 0) {
            findParent(routeItemResps, all, index + 1);
            return;
        }
        for (RouteItemResp itemResp : all) {
            if (itemResp.getRouteId().equals(routeItemResp.getParentId())) {
                routeItemResps.add(itemResp);
                findParent(routeItemResps, all, index + 1);
                return;
            }
        }
    }

    public List<RouteItemResp> findChildren(List<RouteItemResp> routes, Long parentId) {
        List<RouteItemResp> newRoutes = new ArrayList<>();

        for (RouteItemResp route : routes) {
            if (Objects.equals(route.getParentId(), parentId)) {
                newRoutes.add(route);
                route.setChildren(findChildren(routes, route.getRouteId()));
            }
        }

        return newRoutes;
    }

}
